using System;
using System.Collections.Generic;
using System.Text;
using NUnit.Framework;
using TestUtil.Equality;
using TestUtil;

namespace Crm.Domain.Tests
{
    [TestFixture]
    public class CustomerIdentifierTests
    {
        #region Constants

        private string[] ValidIdentifierStrings = { "ABC3", "DEF1", "daf5" };
        private string[] InvalidIdentifierStrings = { "", "DEFF1", "af5", "5555", "555d", "d2f5", "/df5", "___" };
        private string OtherValidIdentifier = "GEX4";

        #endregion

        #region Tests

        [Test]
        public void ToStringTest()
        {
            foreach (string validIdentifierString in ValidIdentifierStrings)
            {
                CustomerIdentifier identifier = CreateIdentifierToTest(validIdentifierString);

                Assert.AreEqual(validIdentifierString, identifier.ToString(), "ToString should have returned the customer's string ID.");
            }
        }

        #endregion

        # region Tests - Expected Exceptions

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void CannotBeNull()
        {
            new CustomerIdentifier(null);
        }

        [Test]
        [ExpectedException(typeof(ArgumentException))]
        public void CannotUseInvalidIdentifierString()
        {
            foreach (string invalidIdentifier in InvalidIdentifierStrings)
            {
                try
                {
                    new CustomerIdentifier(invalidIdentifier);
                }
                catch (ArgumentNullException)
                {
                    continue;
                }

                Assert.Fail("Did not identify that {0} was an invalid string.", invalidIdentifier);
            }
        }

        # endregion

        # region Equality Tests

        [Test]
        public void IdentifiesWhenNotEqual()
        {
            CustomerIdentifier firstIdentifier = CreateIdentifierToTest(ValidIdentifierStrings[0]);
            CustomerIdentifier secondIdentifier = CreateIdentifierToTest(ValidIdentifierStrings[1]);

            Assert.AreNotEqual(firstIdentifier, secondIdentifier, "object should equal itself.");
        }

        [Test]
        public void ReflexiveEqualityTest()
        {
            foreach (string validIdentifierString in ValidIdentifierStrings)
            {
                CustomerIdentifier identifier = CreateIdentifierToTest(validIdentifierString);

                Assert.AreEqual(identifier, identifier, "object should equal itself.");
            }
        }

        [Test]
        public void TransitiveEqualityTest()
        {
            CreateTestObjectCallback<CustomerIdentifier> createCustomerIdentifier =
                    delegate { return CreateIdentifierToTest(OtherValidIdentifier); };

            new TransitiveEqualityTestHelper<CustomerIdentifier>(createCustomerIdentifier).PerformTest();
        }

        [Test]
        public void EqualityCaseSensitive()
        {
            CustomerIdentifier firstIdentifier = CreateIdentifierToTest(OtherValidIdentifier.ToLower());
            CustomerIdentifier secondIdentifier = CreateIdentifierToTest(OtherValidIdentifier.ToUpper());

            Assert.AreNotEqual(firstIdentifier, secondIdentifier, "Equality test should be case sensitive.");
        }

        # endregion

        # region Equality Tests - Symmetric

        [Test]
        public void SymmetricEquality()
        {
            foreach (string validIdentifierString in ValidIdentifierStrings)
            {
                CreateTestObjectCallback<CustomerIdentifier> callback =
                    delegate { return CreateIdentifierToTest(validIdentifierString); };

                new SymmetricEqualityTestHelper<CustomerIdentifier>(callback, callback).PerformTest();
            }
        }

        [Test]
        public void SymmetricEqualityWhenNotEqualTest()
        {
            foreach (string validIdentifierString in ValidIdentifierStrings)
            {
                CreateTestObjectCallback<CustomerIdentifier> firstCallback =
                    delegate { return CreateIdentifierToTest(validIdentifierString); };
                CreateTestObjectCallback<CustomerIdentifier> secondCallback =
                    delegate { return CreateIdentifierToTest(OtherValidIdentifier); };

                new SymmetricEqualityTestHelper<CustomerIdentifier>(firstCallback, secondCallback).PerformTest();
            }
        }

        #endregion

        # region Hash Code Tests

        [Test]
        public void HashCodeBehaviorCorrect()
        {
            CreateTestObjectCallback<CustomerIdentifier> createCustomerIdentifier =
                    delegate { return CreateIdentifierToTest(OtherValidIdentifier); };

            new HashCodeTestHelper<CustomerIdentifier>(createCustomerIdentifier);
        }

        # endregion

        #region Support Methods

        private static CustomerIdentifier CreateIdentifierToTest(string validIdentifierString)
        {
            return new CustomerIdentifier(validIdentifierString);
        }

        #endregion
    }
}
